package com.example.stock.service.impl;

import com.example.stock.controller.dto.MonthPctStatDTO;
import com.example.stock.controller.vo.MonthDetailVO;
import com.example.stock.controller.vo.StockInfoVO;
import com.example.stock.excel.LevelPointDecrease;
import com.example.stock.mapper.MonthDetailMapper;
import com.example.stock.model.MonthDetail;
import com.example.stock.model.MonthSat;
import com.example.stock.service.MonthDataService;
import com.example.stock.service.StockService;
import com.example.stock.service.WuguService;
import com.example.stock.util.StatisticDataUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Log4j2
@Service
public class MonthDataServiceImpl implements MonthDataService {

    @Autowired
    MonthDetailMapper monthDetailMapper;

    WuguService wuguService;

    StockService stockService;

    @Autowired
    public void setWuguService(WuguService wuguService) {
        this.wuguService = wuguService;
    }

    @Autowired
    @Lazy
    public void setStockService(StockService stockService) {
        this.stockService = stockService;
    }

    public Map<String, LevelPointDecrease> getCurrentLevelPointDecreaseMap() {
        Map<String, LevelPointDecrease> levelPointDecreaseMap = new HashMap<>();

        getCurrentLevelPointDecrease().forEach(levelPointDecrease -> {
            levelPointDecreaseMap.put(levelPointDecrease.getStock(), levelPointDecrease);
        });
        return levelPointDecreaseMap;
    }

    @Override
    public List<LevelPointDecrease> getCurrentLevelPointDecrease() {
        return getLevelPointDecreaseMap().get(getMonthPctStatKeys().getFirst());
    }

    Map<String, MonthDetail> currentMonthDetailMap;

    @Override
    public MonthDetail getCurrentMonthDetail(String stock) {
        if (currentMonthDetailMap == null) {
            currentMonthDetailMap = getMonthRawDataByDate(getMonthPctStatKeys().getFirst())
                    .stream().collect(Collectors.toMap(MonthDetail::getStock, i->i));
        }

        return currentMonthDetailMap.get(stock);
    }

    @Override
    public Double getCurrentPrice(String stock) {
        MonthDetail currentMonthDetail = getCurrentMonthDetail(stock);

        return Optional.ofNullable(currentMonthDetail)
                .map(MonthDetail::getClose)
                // 使用orElse方法指定当Optional为空时返回null，否则返回收盘价
                .orElse(null);
    }

    @Override
    public List<MonthDetail> getMonthRawDataByDate(String date) {
        return monthDetailMapper.getMonthDetailByDate(date);
    }

    /**
     * 获取指定股票的月详细数据。
     *
     * @param stock 股票名称
     * @return 指定股票的月详细数据列表
     */
    @Override
    @Cacheable(value = "getMonthRawData", key = "#stock")
    public List<MonthDetail> getMonthRawData(String stock) {
        return monthDetailMapper.getMonthDetailByStock(stock);
    }

    @Override
    public List<MonthPctStatDTO> getMonthPctStatByDate(String month) {

        List<MonthDetail> monthDetails = getMonthRawDataByDate(month);

        List<MonthPctStatDTO> ret = new ArrayList<>();

        monthDetails.forEach(i -> {

            MonthPctStatDTO monthPctStatDTO = new MonthPctStatDTO();
            BeanUtils.copyProperties(i, monthPctStatDTO);
            monthPctStatDTO.setGt60m(i.getGt1200d());

            StockInfoVO stockInfo = stockService.getStockInfo(i.getStock());
            // stockInfo
            monthPctStatDTO.setRank(stockInfo.getRank());
            monthPctStatDTO.setCategory(stockInfo.getCategory());
            monthPctStatDTO.setIndustry(stockInfo.getIndustry());

            ret.add(monthPctStatDTO);
        });
        return ret;
    }

    @Override
    public Map<String, List<MonthDetail>> getMonthRawData(List<String> stocks) {
        if (Objects.isNull(stocks) || stocks.isEmpty()) {
            return null;
        }

        Map<String, List<MonthDetail>> map = new LinkedHashMap<>();
        stocks.forEach(stock -> {
            List<MonthDetail> monthData = getMonthRawData(stock);
            if (!Objects.isNull(monthData)) {
                map.put(stock, monthData);
            }
        });
        return map;
    }

    /**
     * 获取指定股票的月份数据列表
     *
     * @param stock 股票名称
     * @return 指定股票的月份数据列表
     */
    @Override
    @Cacheable(value = "getMonthData", key = "#stock")
    public List<MonthDetailVO> getMonthData(String stock) {

        // lambda 中不能直接使用变量
        Double lpClose[] = {0.0};

        List<MonthDetailVO> collect = getMonthRawData(stock).stream().map(monthDetail -> {
            // 计算 10 分位点连续下跌幅度
            MonthDetailVO monthDetailVO = new MonthDetailVO();
            BeanUtils.copyProperties(monthDetail, monthDetailVO);

            // 分位点大于10的不计算
            if (monthDetail.getLp() > 10) {
                lpClose[0] = 0.0;
                return monthDetailVO;
            }

            // 第一个分位点低于 10 的记录
            if (lpClose[0] == 0.0) {
                lpClose[0] = monthDetail.getClose();
            }

            // 计算10分位点连续下跌幅度
            double v = (monthDetail.getClose() - lpClose[0]) / lpClose[0] * 100;
            monthDetailVO.setLpDecrease(v);

            return monthDetailVO;
        }).collect(Collectors.toList());

        return collect;
    }

    @Override
    public List<LevelPointDecrease> getLevelPointDecreaseByDate(String month) {
        return getLevelPointDecreaseMap().get(month);
    }

    @Override
    public List<MonthSat> getMonthSat() {
        return monthDetailMapper.getMonthSat();
    }

    // 月涨跌 Key
    @Override
    public List<String> getMonthPctStatKeys() {
        return getMonthPctStatKeys(30);
    }

    @Override
    public List<String> getMonthPctStatKeys(int num) {
        return getMonthRawData("上证指数").stream()
                .map(MonthDetail::getDate)
                .sorted(Comparator.comparing(String::toString).reversed())
                .limit(num).toList();
    }

    private List<LevelPointDecrease> getLevelPointDecrease() {
        return StatisticDataUtil.getLevelPointDecrease();
    };

    private Map<String, List<LevelPointDecrease>> getLevelPointDecreaseMap() {
        return getLevelPointDecrease().stream().collect(Collectors.groupingBy(LevelPointDecrease::getDate));
    }

    @Override
    public List<String> getLpDecreaseKeys(int count) {
        return getMonthPctStatKeys(count);
    }
}
